﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Net;

namespace ARGSync
{
    public class GameManager
    {
        private Thread m_Thread = null;
        private List<Game> m_GamePriority = new List<Game>();
        private string m_Running = null;
        private bool m_IsRunning = false;
        private MainForm m_Form = null;
        private delegate void EmptyDelegate();
        private delegate object ObjectDelegate();

        public string GlobalTarget
        {
            get
            {
                if (this.m_GamePriority.Count == 0)
                    return null;
                else
                    return this.m_GamePriority[0].Key;
            }
        }

        public string CurrentRunning
        {
            get { return this.m_Running; }
        }

        public bool IsRunning
        {
            get { return this.m_IsRunning; }
        }

        public GameManager(MainForm form)
        {
            this.m_Form = form;
        }

        public void StartMonitoring()
        {
            this.m_Thread = new Thread(DoMonitoring);
            this.m_Thread.IsBackground = true;
            this.m_Thread.Start();
        }

        public void StopMonitoring()
        {
            this.m_Thread.Abort();
            if (this.m_Running != null)
                this.StopGame(this.m_Running);

            this.m_Running = null;
            this.m_GamePriority.Clear();
            this.m_Thread = null;

            this.m_Form.Invoke(new EmptyDelegate(() => { this.m_Form.UpdateStatistics(); }));
        }

        private void DoMonitoring()
        {
            while (true)
            {
                // Stop game if it already exists.
                if (this.m_Running != null)
                {
                    this.StopGame(this.m_Running);
                    this.m_Running = null;
                }
                this.m_IsRunning = false;

                // Get a new game priority list.
                WebClient wc = new WebClient();
                string res = wc.DownloadString(Program.SourceURL);
                string[] spl = res.Split(new char[] { '\n' });
                this.m_GamePriority.Clear();

                // Add the games to the game priority.
                foreach (string r in spl)
                {
                    try
                    {
                        this.m_GamePriority.Add(Program.Games[r]);
                    }
                    catch (KeyNotFoundException)
                    {
                    }
                }

                // Loop through the list of games, until we find one
                // we can start.
                for (int i = 0; i < this.m_GamePriority.Count; i++)
                {
                    Game g = this.m_GamePriority[i];
                    if (this.HasGame(g))
                    {
                        this.m_Running = g.Key;
                        this.StartGame(this.m_Running);
                        break;
                    }
                }

                // Get the form to update the current information.
                this.m_Form.Invoke(new EmptyDelegate(() => { this.m_Form.UpdateStatistics(); }));

                // Run a thread to check when the process comes online.
                new Thread(() =>
                {
                    string proc = Program.Games[this.m_Running].ProcessName;
                    int i = 0;
                    while (Process.GetProcessesByName(proc).Length == 0 && i < 10)
                    {
                        Thread.Sleep(1000);
                        i += 1;
                        this.m_Form.Invoke(new EmptyDelegate(() => { this.m_Form.SetWaitTime(10 - i); }));
                    }

                    if (i == 10 && Process.GetProcessesByName(proc).Length == 0)
                    {
                        // Check to see whether it didn't start at all.
                        this.m_Form.Invoke(new EmptyDelegate(() => { this.m_Form.ForceStop(); }));
                    }
                    else
                    {
                        this.m_IsRunning = true;
                        this.m_Form.Invoke(new EmptyDelegate(() => { this.m_Form.UpdateStatistics(); }));
                        this.m_Form.Invoke(new EmptyDelegate(() => { this.m_Form.EnableStop(); }));
                    }
                }).Start();

                // Wait 10 minutes before doing it all again.
                this.m_Form.Invoke(new EmptyDelegate(() => { this.m_Form.ResetCheckTime(); }));
                Thread.Sleep(1000 * 60 * 10);
            }
        }

        private void StartGame(string key)
        {
            int appid = Program.Games[key].AppID;
            Process.Start("steam://run/" + appid);
        }

        private bool HasGame(Game g)
        {
            return (bool)this.m_Form.Invoke(new ObjectDelegate(() => { return this.m_Form.HasGame(g.Key); }));
        }

        private void StopGame(string key)
        {
            string proc = Program.Games[key].ProcessName;
            Process[] toterm = Process.GetProcessesByName(proc);
            foreach (Process t in toterm)
                t.Kill();
        }
    }
}
